import { app, shell, BrowserWindow, ipcMain, dialog, protocol } from 'electron'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../build/icon.png?asset'
import * as path from 'path'
import * as fs from 'fs'
import * as mm from 'music-metadata'

function createWindow(): void {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 1200,
    height: 750,
    minHeight: 750,
    minWidth: 1200,
    resizable: false,
    show: false,
    frame: false,  // 设置无边框
    backgroundColor: '#00000000',//窗口底色为透明色
    autoHideMenuBar: true,
    ...(process.platform === 'linux' ? { icon } : {}),
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false,
      contextIsolation: false, // 如果你使用 Node.js 功能，这个可能需要设置为 false
      nodeIntegration: true, // 开启 Node 集成
      webSecurity: false
    }
  })

  mainWindow.on('ready-to-show', () => {
    mainWindow.show()
  })
  // 1. 窗口 最小化
  ipcMain.on('window-min', function () {
    // 收到渲染进程的窗口最小化操作的通知，并调用窗口最小化函数，执行该操作
    mainWindow.minimize()
  })
  // 2. 窗口 最大化、恢复
  ipcMain.on('window-max', function () {
    if (mainWindow.isMaximized()) {
      // 为true表示窗口已最大化
      console.log('Window is currently maximized, restoring it.');
      mainWindow.restore() // 将窗口恢复为之前的状.
    } else {
      console.log('Window is not maximized, maximizing it.');
      mainWindow.maximize()
    }
  })
  // 3. 关闭窗口
  ipcMain.on('window-close', function () {
    mainWindow.close()
  })

  mainWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url)
    return { action: 'deny' }
  })
  //外部浏览器打开链接
  ipcMain.on('new-window', function(e, url) {
    e.preventDefault();
    require('electron').shell.openExternal(url);
  })

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
  }

  mainWindow.webContents.openDevTools()
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
  // Set app user model id for windows
  electronApp.setAppUserModelId('com.electron')

  // Default open or close DevTools by F12 in development
  // and ignore CommandOrControl + R in production.
  // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
  app.on('browser-window-created', (_, window) => {
    optimizer.watchWindowShortcuts(window)
  })

  // IPC test
  ipcMain.on('ping', () => console.log('pong'))

  // 注册自定义协议，必须在 app.ready 之后
  protocol.registerFileProtocol('local-music', (request, callback) => {
    const url = request.url.replace('local-music://', '')
    try {
      // 返回文件路径和 MIME 类型
      return callback({
        path: decodeURI(url),
        mimeType: 'audio/mpeg'
      })
    } catch (error) {
      console.error('Protocol Error:', error)
      callback({ error: -2 })
    }
  })

  createWindow()

  app.on('activate', function () {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
  // 处理跨域访问外部网页
  app.commandLine.appendSwitch("disable-site-isolation-trials");
  app.commandLine.appendSwitch('disable-features', 'BlockInsecurePrivateNetworkRequests,PrivateNetworkAccessSendPreflights');

  // 在开发环境下添加热重载
  if (process.env.NODE_ENV === 'development') {
    if (mainWindow) {
      mainWindow.webContents.on('did-finish-load', () => {
        mainWindow.webContents.on('devtools-reload-page', () => {
          mainWindow.webContents.reload()
        })
      })
    }
  }

  try {
    require('electron-reloader')(module, {
      debug: true,
      watchRenderer: true
    })
  } catch (_) { console.log('Error') }
})

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

// In this file you can include the rest of your app"s specific main process
// code. You can also put them in separate files and require them here.

// 处理选择目录
ipcMain.handle('select-dirs', () => {
  return dialog.showOpenDialog({
    properties: ['openDirectory']
  })
})

// 扫描音乐文件
ipcMain.handle('scan-music-files', async (event, dirs: string[]) => {
  const musicFiles: any[] = []
  
  for (const dir of dirs) {
    try {
      const files = await scanDir(dir)
      for (const file of files) {
        if (file.toLowerCase().endsWith('.mp3')) {
          try {
            // 使用 Buffer 读取文件并解析元数据
            const buffer = fs.readFileSync(file)
            const metadata = await mm.parseBuffer(buffer, {
              mimeType: 'audio/mpeg',
              duration: true
            })

            const stats = fs.statSync(file)
            const fileName = path.basename(file, '.mp3')
            
            // 从文件名解析歌手和歌名
            let artist = '未知歌手'
            let title = fileName
            if (fileName.includes(' - ')) {
              [artist, title] = fileName.split(' - ')
            }
            
            // 计算时长（毫秒）
            let duration = 0
            if (metadata.format.duration) {
              duration = Math.floor(metadata.format.duration * 1000)
            } else {
              // 如果无法从元数据获取时长，尝试从音频数据计算
              duration = Math.floor((metadata.format.numberOfSamples || 0) / 
                (metadata.format.sampleRate || 44100) * 1000)
            }
            
            musicFiles.push({
              name: title,
              singer: [{
                id: 0,
                name: artist
              }],
              duration: duration,
              url: `local-music://${file.replace(/\\/g, '/')}`,
              size: stats.size
            })
          } catch (error) {
            console.error('解析音乐文件失败:', path.basename(file), error)
            try {
              // 如果元数据解析失败，尝试使用 ffprobe 获取时长
              const { execSync } = require('child_process')
              const ffprobeOutput = execSync(
                `ffprobe -v quiet -print_format json -show_format "${file}"`,
                { encoding: 'utf-8' }
              )
              const ffprobeData = JSON.parse(ffprobeOutput)
              const duration = Math.floor(parseFloat(ffprobeData.format.duration) * 1000)

              const fileName = path.basename(file, '.mp3')
              let artist = '未知歌手'
              let title = fileName
              if (fileName.includes(' - ')) {
                [artist, title] = fileName.split(' - ')
              }
              
              musicFiles.push({
                name: title,
                singer: [{
                  id: 0,
                  name: artist
                }],
                duration: duration || 0,
                url: `local-music://${file.replace(/\\/g, '/')}`,
                size: fs.statSync(file).size
              })
            } catch (ffprobeError) {
              console.error('获取音频时长失败:', ffprobeError)
              // 如果所有方法都失败，添加基本信息
              musicFiles.push({
                name: path.basename(file, '.mp3'),
                singer: [{ id: 0, name: '未知歌手' }],
                duration: 0,
                url: `local-music://${file.replace(/\\/g, '/')}`,
                size: fs.statSync(file).size
              })
            }
          }
        }
      }
    } catch (error) {
      console.error('扫描目录失败:', dir, error)
    }
  }
  
  return musicFiles
})

// 递归扫描目录
async function scanDir(dir: string): Promise<string[]> {
  const files: string[] = []
  const items = fs.readdirSync(dir)
  
  for (const item of items) {
    const fullPath = path.join(dir, item)
    const stats = fs.statSync(fullPath)
    
    if (stats.isDirectory()) {
      files.push(...await scanDir(fullPath))
    } else if (stats.isFile()) {
      files.push(fullPath)
    }
  }
  
  return files
}
